﻿using BCCommon;
using BCCommon.Enums;
using BCData.Website.UserAddress;
using BCDto.Website.UserAddress;
using BCEntity.Website.UserAddress;
using BCEntity.Common.EntityNameConst;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BCData.Common.Area;

namespace BCService.Website.UserAddress
{
    public class UserAddressService : IUserAddressService
    {
        private readonly IDatabaseContext databaseContext;
        private readonly IApplicationContextService applicationContextService;
        private readonly IRedisService redisService;
        private readonly IUserAddressData userAddressData;
        private readonly IProvinceData provinceData;
        private readonly ICityData cityData;
        private readonly ICountyData countyData;
        private readonly string key = string.Format("{0}", EntityNameConst.UserAddressEntity);

        public UserAddressService(IDatabaseContext databaseContext,
            IApplicationContextService applicationContextService,
            IRedisService redisService,
            IUserAddressData userAddressData,
            IProvinceData provinceData,
            ICityData cityData,
            ICountyData countyData)
        {
            this.databaseContext = databaseContext;
            this.applicationContextService = applicationContextService;
            this.redisService = redisService;
            this.userAddressData = userAddressData;
            this.provinceData = provinceData;
            this.cityData = cityData;
            this.countyData = countyData;
        }

        #region 检查用户地址是否存在
        public bool Exists(long userAddressId)
        {
            return this.userAddressData.Exists(userAddressId).GetAwaiter().GetResult();
        }
        #endregion

        #region 添加用户地址
        public UserAddressDto Add(UserAddressRequestDto requestDto)
        {
            if (!this.provinceData.CheckProvinceExistsById(requestDto.ProvinceId))
            {
                throw new ArgumentException("此省份不存在");
            }
            if (!this.cityData.CheckExistsById(requestDto.CityId))
            {
                throw new ArgumentException("此城市不存在");
            }
            if (requestDto.CountyId.HasValue&&!this.countyData.CheckExistsById(requestDto.CountyId.Value))
            {
                throw new ArgumentException("此区县不存在");
            }
            var provinceEntity = this.provinceData.GetProvince(requestDto.ProvinceId);
            var cityEntity = this.cityData.GetCity(requestDto.CityId);
            
            var entity = requestDto.As<UserAddressEntity>();
            entity.UserId = applicationContextService.User.UserId;
            entity.ProvinceCode = provinceEntity.ProvinceCode;
            entity.ProvinceName = provinceEntity.ProvinceName;
            entity.CityCode = cityEntity.CityCode;
            entity.CityName = cityEntity.CityName;
            if (requestDto.CountyId.HasValue)
            {
                var countyEntity = this.countyData.GetCounty(requestDto.CountyId.Value);
                entity.CountyCode = countyEntity.CountyCode;
                entity.CountyName = countyEntity.CountyName;
            }

            databaseContext.BeginTransaction();
            
            if (entity.IsDefault&&this.userAddressData.ExistsByUserId(applicationContextService.User.UserId).Result)
            {
                var cancelResult = this.userAddressData.CancelIsDefault(applicationContextService.User.UserId).Result;
                if (!cancelResult)
                {
                    throw new ArgumentException("取消默认地址失败!");
                }
            }
            var result = this.userAddressData.Add(entity).Result;
            if (result == null)
            { 
                throw new ArgumentException("添加地址失败!");
            }
            databaseContext.Commit();
            string cacheKey = this.redisService.GetSingleRootKey(key,"userId", applicationContextService.User.UserId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            return result.As<UserAddressDto>();
        }
        #endregion

        #region 修改用户地址
        public UserAddressDto Update(UserAddressPutDto putDto)
        {
            if (!this.Exists(putDto.UserAddressId))
            {
                throw new ArgumentException("此记录不存在!");
            }
            if (!this.provinceData.CheckProvinceExistsById(putDto.ProvinceId))
            {
                throw new ArgumentException("此省份不存在");
            }
            if (!this.cityData.CheckExistsById(putDto.CityId))
            {
                throw new ArgumentException("此城市不存在");
            }
            if (putDto.CountyId.HasValue && !this.countyData.CheckExistsById(putDto.CountyId.Value))
            {
                throw new ArgumentException("此区县不存在");
            }
            var provinceEntity = this.provinceData.GetProvince(putDto.ProvinceId);
            var cityEntity = this.cityData.GetCity(putDto.CityId);
            var entity = putDto.As<UserAddressEntity>();
            entity.UserId = applicationContextService.User.UserId;
            entity.ProvinceCode = provinceEntity.ProvinceCode;
            entity.ProvinceName = provinceEntity.ProvinceName;
            entity.CityCode = cityEntity.CityCode;
            entity.CityName = cityEntity.CityName;
            if (putDto.CountyId.HasValue)
            {
                var countyEntity = this.countyData.GetCounty(putDto.CountyId.Value);
                entity.CountyCode = countyEntity.CountyCode;
                entity.CountyName = countyEntity.CountyName;
            }

            databaseContext.BeginTransaction();

            if (entity.IsDefault && this.userAddressData.ExistsByUserId(applicationContextService.User.UserId).Result)
            {
                var cancelResult = this.userAddressData.CancelIsDefault(applicationContextService.User.UserId).Result;
                if (!cancelResult)
                {
                    throw new ArgumentException("取消默认地址失败!");
                }
            }

            var result = this.userAddressData.Update(entity).Result;
            if (result == null)
            {
                throw new ArgumentException("修改地址失败!");
            }
            databaseContext.Commit();

            string cacheKey = this.redisService.GetSingleRootKey(key, "userId", applicationContextService.User.UserId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            cacheKey = this.redisService.GetSingleRootKey(key, "userAddressId", entity.UserAddressId);
            this.redisService.DeleteAsync(cacheKey);
            return result.As<UserAddressDto>();
        }
        #endregion

        #region 设置默认地址
        public bool SettingIsDefault(long userAddressId)
        {
            if (!this.Exists(userAddressId))
            {
                throw new ArgumentException("此记录不存在!");
            }

            this.databaseContext.BeginTransaction();
            if (this.userAddressData.ExistsByUserId(applicationContextService.User.UserId).Result)
            {
                var cancelResult = this.userAddressData.CancelIsDefault(applicationContextService.User.UserId).Result;
                if (!cancelResult)
                {
                    throw new ArgumentException("取消默认地址失败!");
                }
            }
            var result = this.userAddressData.SettingIsDefault(userAddressId).Result;
            if (!result)
            {
                throw new ArgumentException("设置默认地址失败!");
            }
            databaseContext.Commit();
            string cacheKey = this.redisService.GetSingleRootKey(key, "userId", applicationContextService.User.UserId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            cacheKey = this.redisService.GetKey(key, userAddressId);
            this.redisService.DeleteAsync(cacheKey);
            return result;
        }
        #endregion

        #region 删除用户地址
        public bool Delete(long userAddressId)
        {
            if (!this.Exists(userAddressId))
            {
                throw new ArgumentException("此记录不存在!");
            }

            var result = this.userAddressData.Delete(userAddressId).GetAwaiter().GetResult();

            string cacheKey = this.redisService.GetSingleRootKey(key, "userId", applicationContextService.User.UserId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            cacheKey = this.redisService.GetKey(key, userAddressId);
            this.redisService.DeleteAsync(cacheKey);
            return result;
        }
        #endregion

        #region 获取用户地址
        public UserAddressDto Get(long userAddressId)
        {
            string cacheKey = this.redisService.GetKey(key, userAddressId);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.userAddressData.GetEntity(userAddressId).GetAwaiter().GetResult();
                return data;
            }, TimeSpan.FromMinutes(30));
            return result.As<UserAddressDto>();
        }
        #endregion

        #region 获取用户地址总数
        public int Count(long userId)
        {
            return this.userAddressData.Count(userId).GetAwaiter().GetResult();
        }
        #endregion

        #region 获取用户地址列表
        public IEnumerable<UserAddressDto> GetList(long userId)
        {
            string cacheKey = this.redisService.GetKey(key, userId);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                return this.userAddressData.GetList(userId).GetAwaiter().GetResult();
            }, TimeSpan.FromMinutes(30));
            return result.As<IEnumerable<UserAddressDto>>();
        }
        #endregion

        #region 获取用户地址分页
        public PageableList<UserAddressDto> Query(long? userId, DateTime? start, DateTime? end, string sortName, bool? ascending, int pageIndex, int pageSize)
        {
            string cacheKey = this.redisService.GetKey(key, userId, start, end, sortName, ascending, pageIndex, pageSize);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.userAddressData.Query(userId, start, end, sortName, ascending, pageIndex, pageSize).GetAwaiter().GetResult();
                return new PageableList<UserAddressDto>
                {
                    Count = data.Item2,
                    Items = data.Item1.As<IEnumerable<UserAddressDto>>(),
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    ServerTime = DateTime.Now
                };
            }, TimeSpan.FromMinutes(30));

            return result;
        }
        #endregion
    }
}